1 module hip.systems.gamepads.xbox;
2 import hip.util.system;
3 import hip.systems.gamepad;
4 
5 ///Refer to https://docs.microsoft.com/en-us/uwp/api/windows.gaming.input.gamepadbuttons?view=winrt-20348
6 enum HipXboxGamepadButton : int
7 {
8     none            = 0,     ///No button.
9     menu            = 1,     ///Menu button.
10     view            = 1<<1,  ///View button.
11     a               = 1<<2,  ///A button.
12     b               = 1<<3,  ///B button.
13     x               = 1<<4,  ///X button.
14     y               = 1<<5,  ///Y button.
15     dPadUp          = 1<<6,  ///D-pad up.
16     dPadDown        = 1<<7,  ///D-pad down.
17     dPadLeft        = 1<<8,  ///D-pad left.
18     dPadRight       = 1<<9,  ///D-pad right.
19     leftShoulder    = 1<<10, ///Left bumper.
20     rightShoulder   = 1<<11, ///Right bumper.
21     leftThumbstick  = 1<<12, ///Left stick.
22     rightThumbstick = 1<<13, ///Right stick.
23     paddle1         = 1<<14, ///The first paddle.
24     paddle2         = 1<<15, ///The second paddle.
25     paddle3         = 1<<16, ///The third paddle.
26     paddle4         = 1<<17, ///The fourth paddle.
27 }
28 
29 
30 pragma(inline, true) 
31 bool isXboxGamepadButtonPressed(int gamepadState, HipXboxGamepadButton btn){return (gamepadState & btn) == btn;}
32 
33 struct HipInputXboxGamepadState
34 {
35     int buttons;
36     double leftAnalogX;
37     double leftAnalogY;
38     double rightAnalogX;
39     double rightAnalogY;
40     double leftTrigger;
41     double rightTrigger;
42 }
43 
44 
45 //////// External API ////////
46 
47 extern(System) __gshared
48 {
49     ubyte* function() HipGamepadCheckConnectedGamepads;
50     HipGamepadBatteryStatus function(ubyte id) HipGamepadGetBatteryStatus;
51     HipInputXboxGamepadState function(ubyte id) HipGamepadGetXboxGamepadState;
52     bool function(ubyte id) HipGamepadIsWireless;
53     ubyte function() HipGamepadQueryConnectedGamepadsCount;
54 
55     void function(
56         ubyte id,
57         double leftMotor,
58         double rightMotor,
59         double leftTrigger,
60         double rightTrigger
61     ) HipGamepadSetXboxGamepadVibration;
62 }
63 
64 
65 
66 extern(D):
67 void initXboxGamepadInput()
68 {
69     __gshared bool hasInit = false;
70     if(hasInit)
71         return;
72     version(Windows)
73     {
74         string[] errors = dllImportVariables!(
75             HipGamepadCheckConnectedGamepads,
76             HipGamepadGetBatteryStatus,
77             HipGamepadGetXboxGamepadState,
78             HipGamepadIsWireless,
79             HipGamepadQueryConnectedGamepadsCount,
80             HipGamepadSetXboxGamepadVibration
81         );
82         foreach(err; errors)
83         {
84             import hip.console.log;
85             logln("HIPREME_ENGINE: Could not load ", err);
86         }
87     }
88 
89     hasInit = true;
90 }
91 
92 //////// End External API ////////
93 
94 /** Engine task:
95 * Send gamepad connect and disconnect events
96 * Poll every connected gamepad every frame
97 * Should always return a neutral state for every disconnected gamepad
98 *
99 * Game task:
100 * Check gamepad count
101 * Decide what will do with connected gamepads
102 */
103 class HipXBOXGamepad : IHipGamepadImpl
104 {
105     void poll(HipGamepad pad)
106     {
107         HipInputXboxGamepadState state = HipGamepadGetXboxGamepadState(pad.getId);
108         int b = state.buttons;
109         with(pad)
110         {
111             setAnalog(HipGamepadAnalogs.leftStick, [state.leftAnalogX, state.leftAnalogY, 1]);
112             setAnalog(HipGamepadAnalogs.rightStick, [state.rightAnalogX, state.rightAnalogY, 1]);
113 
114             leftTrigger = state.leftTrigger;
115             rightTrigger = state.rightTrigger;
116             setButtonPressed(HipGamepadButton.xboxY, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.y));
117             setButtonPressed(HipGamepadButton.xboxX, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.x));
118             setButtonPressed(HipGamepadButton.xboxA, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.a));
119             setButtonPressed(HipGamepadButton.xboxB, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.b));
120 
121             setButtonPressed(HipGamepadButton.dPadUp, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.dPadUp));
122             setButtonPressed(HipGamepadButton.dPadLeft, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.dPadLeft));
123             setButtonPressed(HipGamepadButton.dPadDown, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.dPadDown));
124             setButtonPressed(HipGamepadButton.dPadRight, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.dPadRight));
125 
126             setButtonPressed(HipGamepadButton.left1, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.leftShoulder));
127             setButtonPressed(HipGamepadButton.right1, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.rightShoulder));
128             // setButtonPressed(HipGamepadButton.left2, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.pa));
129             // setButtonPressed(HipGamepadButton.right2, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.dPadRight));
130 
131             setButtonPressed(HipGamepadButton.left3, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.leftThumbstick));
132             setButtonPressed(HipGamepadButton.right3, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.rightThumbstick));
133 
134             setButtonPressed(HipGamepadButton.start, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.menu));
135             setButtonPressed(HipGamepadButton.select, isXboxGamepadButtonPressed(b, HipXboxGamepadButton.view));
136         }
137     }
138 
139     void setVibrating(ubyte id, double leftMotor, double rightMotor, double leftTrigger, double rightTrigger)
140     {
141         HipGamepadSetXboxGamepadVibration(id, 
142             leftMotor,
143             rightMotor,
144             leftTrigger,
145             rightTrigger
146         );
147     }
148     bool isWireless(ubyte id){return HipGamepadIsWireless(id);}
149     HipGamepadBatteryStatus getBatteryStatus(ubyte id){return HipGamepadGetBatteryStatus(id);}
150 }